/*
* Conditions Of Use
*
* This software was developed by employees of the Sigmatrix(Beijing) Corporation.
* This software is provided by sigmatrix as a service and is expressly
* provided "AS IS."  Sigmatrix MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY.  Sigmatrix does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
* Permission to use this software is contingent upon your acceptance
* of the terms of this agreement.
*
*/
package com.sigmatrix.h5.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.sigmatrix.h5.dto.BaseQRCodeData;
import com.sigmatrix.h5.dto.PackScanData;
import com.sigmatrix.h5.dto.ProductData;
import com.sigmatrix.h5.entity.FirstLevelQRCode;
import com.sigmatrix.h5.entity.MultistageLevelQRCode;
import com.sigmatrix.h5.enums.PackScanOperTypeEnum;
import com.sigmatrix.h5.enums.ResponseEnum;
import com.sigmatrix.h5.exception.ServiceException;
import com.sigmatrix.h5.response.Response;
import com.sigmatrix.h5.service.MultistageLevelQrCodeService;
import com.sigmatrix.h5.service.PackScanService;
import com.sigmatrix.h5.service.ProductService;
import com.sigmatrix.h5.service.QrCodeService;
import com.sigmatrix.h5.service.common.impl.BaseServiceImpl;
import com.sigmatrix.h5.utils.Cons;
import com.sigmatrix.h5.web.vo.PackScanOperationVo;
import com.sigmatrix.h5.web.vo.PackScanVo;
import com.sigmatrix.h5.web.vo.QRCodeVo;

/**
 *@ClassName: PackSanServiceImpl
 *@Description: 包装管理业务层接口实现
 *@author youjun
 *@date 2017年8月16日 下午8:07:08
 */
@Service(value="packScanService")
public class PackScanServiceImpl extends BaseServiceImpl<MultistageLevelQRCode> implements PackScanService {

	/**扫码业务层接口*/
	@Autowired
	private transient QrCodeService qRCodeService;
	
	/**多级码业务层接口*/
	@Autowired
	private transient MultistageLevelQrCodeService multistageLevelQRCodeService;
	
	/**产品业务层接口*/
	@Autowired
	private transient ProductService productService;
	
	/**(non-Javadoc)
	 *@Title: scanCode
	 *@Description: 
	 *@see com.sigmatrix.sc.handheld.inter.service.PackScanService#scanCode(com.sigmatrix.sc.handheld.inter.web.vo.packmanage.PackScanVo)
	 *@author youjun
	 *@date 2017年8月16日 下午8:10:18
	 */
	@Override
	public Response scanCode(final PackScanVo packScanVo) throws ServiceException {

		Response validateResponse = validateScanCodeParams(packScanVo);
		if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
			return validateResponse;
		}
		final String enterpriseCode = packScanVo.getEnterpriseCode();
		final Map<String, Object> map = new HashMap<String, Object>();
		final QRCodeVo qRCodeVo = new QRCodeVo();
		qRCodeVo.setEnterpriseCode(packScanVo.getEnterpriseCode());
		qRCodeVo.setCode(packScanVo.getCode());
		qRCodeVo.setCodeType(packScanVo.getCodeType());
		qRCodeVo.setOperationType(packScanVo.getOperationType());
		validateResponse = qRCodeService.queryCodeByCode(qRCodeVo, map, -1);
		if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
			return validateResponse;
		}
		final ProductData product = (ProductData) map.get("product"); // 产品信息
		final Map<Integer, String> packStandardMap = product.getPackStandardMap(); // 包装规格map
		final List<Integer> packStandardLevelList = product.getPackStandardLevelList(); // 包装level的集合,从小到大排序
		final int bigLevel = packStandardLevelList.get(packStandardLevelList.size()-1); // 最大包装级别
		final int packLevel = product.getProductUnit().intValue(); // 产品的包装单位级别
		final int codeLevel = (int) map.get("codeLevel"); // 所扫码的级别
		final PackScanData packScanData = new PackScanData(); // 返回给手持的信息
		packScanData.setProductId(product.getProductId());
		packScanData.setProductName(product.getProductName());
		// 包装码,初始值取当前扫码的多级码(后面逻辑会判断是否扫的是包装码,会进行相应的替换)
		MultistageLevelQRCode packMultis = (MultistageLevelQRCode) map.get("multistageLevelQRCode");
		
		final int operationType = packScanVo.getOperationType(); // 当前操作
		if(operationType==PackScanOperTypeEnum.GROUP_OR_FILL_BOX.getId()) { // 组/补箱操作,扫描的必须是包装码
			if(codeLevel!=packLevel) {
				return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
						new StringBuilder("组箱操作扫的必须是").append(packStandardMap.get(packLevel))
						.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
			}
			packScanData.setCount(packMultis.getChildNum()); // 下级码数量
			final int subNum = productService.getCountHaveSpecifiedLevelCount(product, packLevel, packLevel-1); // 包装码的包装规格下级数量
			packScanData.setSurplusSize(subNum-packMultis.getChildNum());
			
		}else if(operationType==PackScanOperTypeEnum.SPLIT_BOX.getId()) { // 拆箱操作,扫描的是包装的下级码
			if(codeLevel!=packLevel-1) {
				return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
						new StringBuilder("拆箱操作扫的必须是").append(packStandardMap.get(packLevel-1))
						.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
			}
			// 过了if说明扫的是包装的下级码,判断是否是一级码,最终获得当前扫码的上级码(即包装码),查出其信息
			String parentCode = ""; // 上级码,即包装码
			if(codeLevel==1) { // 当前的产品的包装单位级别为2
				final FirstLevelQRCode firstLevelQRCode = (FirstLevelQRCode) map.get("firstLevelQRCode");
				parentCode = firstLevelQRCode.getParentCode();
			}else{
				parentCode = packMultis.getParentCode();
			}
			if(StringUtils.isBlank(parentCode)) {
				return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
						new StringBuilder("拆箱操作扫的").append(packStandardMap.get(codeLevel))
						.append("没有关联").append(packStandardMap.get(codeLevel+1)).toString());
			}
			// 找到对应的包装码信息
			packMultis = multistageLevelQRCodeService.findMultistageLevelQRCodeByQRCode(enterpriseCode, 
					parentCode, Cons.CODE_TYPE_STANDARD, false);
			if(packMultis==null) {
				return new Response(Cons.RESPONSE_CODE_NO_DATA, new StringBuilder("拆箱操作扫的").append(packStandardMap.get(codeLevel))
						.append("关联的").append(packStandardMap.get(codeLevel+1)).append("不存在").toString());
			}
			packScanData.setCount(packMultis.getChildNum()); // 下级码数量
		}else if(operationType==PackScanOperTypeEnum.GROUP_OR_FILL_STACK.getId()) { // 补垛操作
			// 组/补垛操作:扫原垛下的箱,获得对应的垛码(顶级码)
			if(codeLevel!=packLevel) {
				return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
						new StringBuilder("组垛操作扫的必须是").append(packStandardMap.get(packLevel))
						.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
			}
			// 查找当前码指定级别的码（这里取最大级别,即顶级码）
			final MultistageLevelQRCode bigLevelMultis = multistageLevelQRCodeService.getSpecifiedUpLevelCode(enterpriseCode, packMultis.getPackContent(), 
					codeLevel, false, bigLevel);
			if(bigLevelMultis==null){
				packScanData.setStackCode(""); // 垛码返回为"",说明要组新垛了
				packScanData.setCount(0); // 所包含的包装码数量为0
			}else{
				packScanData.setStackCode(bigLevelMultis.getPackContent()); // 垛码
				if(packLevel+2<bigLevel) { // 目前只支持最高规格最多比包装码大两级
					return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, "目前只支持最高规格最多比包装码大两级");
				}
				final Map<String, Object> resultMap = multistageLevelQRCodeService.getInventedCodeRelatedInfo(enterpriseCode, bigLevelMultis.getPackContent(), bigLevelMultis.getPackLevel(), 
						false, packLevel, false);
				final int packCount = (int) resultMap.get("packCodeCount");
				packScanData.setCount(packCount); // 所包含的包装码数量
				// 判断包装码和顶级码直接是否还存在虚拟码,若存在,需要返回
				if(packLevel+1!=bigLevel) {
					final MultistageLevelQRCode layerMultis = multistageLevelQRCodeService.findMultistageLevelQRCodeByQRCode(enterpriseCode, 
							packMultis.getParentCode(), Cons.CODE_TYPE_STANDARD, false);
					packScanData.setLayerCode(packMultis.getParentCode());
					packScanData.setLayerName(packStandardMap.get(packLevel+1));
					final int levelNum = layerMultis.getChildNum(); // 下级数量
					final int subNum = productService.getCountHaveSpecifiedLevelCount(product, packLevel+1, packLevel); // 包装上级码的包装规格下级数量
					final int surplusSize = subNum-levelNum;
					packScanData.setLayerSurplusSize(surplusSize); // 剩余空位数
					if(surplusSize==0) { // 剩余空位为0,需查找当前垛有无空的上级码,有则返回
						final int bigHavingPackSubNum = productService.getCountHaveSpecifiedLevelCount(product, 
								bigLevel, packLevel);
						// 当前只支持最高级别码比包装码最多大两级
						if(packCount<bigHavingPackSubNum) {
							getEmptyParent(bigLevelMultis, product, packScanData);
						}
					}
				}
			}
		}else if(operationType==PackScanOperTypeEnum.SPLIT_STACK.getId()) { // 拆垛操作
			if(codeLevel!=packLevel) {
				return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
						new StringBuilder("拆垛操作扫的必须是").append(packStandardMap.get(packLevel))
						.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
			}
			
			// 获得垛码信息
			final MultistageLevelQRCode bigLevelMultis = multistageLevelQRCodeService.getSpecifiedUpLevelCode(enterpriseCode, packMultis.getPackContent(), 
						codeLevel, false, bigLevel);
			if(bigLevelMultis==null){
				return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
						new StringBuilder("拆垛操作扫的").append(packStandardMap.get(packLevel))
						.append("无对应").append(packStandardMap.get(bigLevel)).toString());
			}
			packScanData.setStackCode(bigLevelMultis.getPackContent());
			// 返回找到的垛码对应的包装码数量
			final Map<String, Object> resultMap = multistageLevelQRCodeService.getInventedCodeRelatedInfo(enterpriseCode, bigLevelMultis.getPackContent(), bigLevelMultis.getPackLevel(), 
					false, packLevel, false);
			packScanData.setCount((Integer) resultMap.get("packCodeCount")); // 所包含的包装码数量
			
		}else if(operationType==PackScanOperTypeEnum.ADD_NEW_STACK.getId()) { // 新增垛操作
			if(packLevel+2<bigLevel) {
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "当前只支持包装单位与最大单位之间的最大差值为2");
			}
			final String bigCode = multistageLevelQRCodeService.generatedMultistageQRCode(enterpriseCode, packMultis , "", bigLevel, Cons.CODE_CATEGORY_PREFIX_STACK);
			packScanData.setStackCode(bigCode);
			packScanData.setCount(0); // 初始时为0
			final int subNum = productService.getCountHaveSpecifiedLevelCount(product, bigLevel, packLevel);
			packScanData.setSurplusSize(subNum );
		}else{
			return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "暂不支持该操作");
		}
		packScanData.setCode(packMultis.getPackContent());
		packScanData.setFriendlyCode(packMultis.getFriendlyCode());
		packScanData.setFriendlyCodeFront(packMultis.getFriendlyCodeFront());
		packScanData.setFriendlyCodeEnd(packMultis.getFriendlyCodeEnd());
		packScanData.setSeqNum(packMultis.getSeqNum());
		packScanData.setBigUnit(packStandardMap.get(bigLevel));
		packScanData.setPackUnit(packStandardMap.get(packLevel));
		packScanData.setPackUnderUnit(packStandardMap.get(packLevel-1));
		
		return new Response(ResponseEnum.SUCCESS, packScanData);
	}

	/**
	 *@Title: getEmptyParent
	 *@Description: 获得一个空的上级码
	 *@return void
	 *@author youjun
	 *@date 2017年8月21日 下午9:46:11
	 *@param bigLevelMultis 最高规格码
	 *@param product 产品信息
	 *@param packScanData 前台扫码返回信息
	 * @throws ServiceException 
	 */
	private void getEmptyParent(final MultistageLevelQRCode bigLevelMultis, final ProductData product, final PackScanData packScanData) throws ServiceException {

		if(bigLevelMultis==null
				||product==null
				||packScanData==null) {
			throw new ServiceException("获得空层传递参数有误");
		}
		
		if(product.getBigLevel()-2>product.getProductUnit()) {
			throw new ServiceException("当前仅支持最高规格最多比包装单位大两级");
		}
		// 最高规格的所有子码
		final int childNum = bigLevelMultis.getChildNum();
		final Map<Integer, String> packStandardMap = product.getPackStandardMap();
		final Map<Integer, Integer> packStandardSubNumMap = product.getPackStandardSubNumMap();
		final MultistageLevelQRCode multisQRCodeCondition = new MultistageLevelQRCode();
		multisQRCodeCondition.setChildNum(0);
		multisQRCodeCondition.setEnterpriseCode(bigLevelMultis.getEnterpriseCode());
		multisQRCodeCondition.setParentCode(bigLevelMultis.getPackContent());
		multisQRCodeCondition.setChildNum(0);
		final List<MultistageLevelQRCode> childList = multistageLevelQRCodeService.findMultistageLevelQRCodeByCondition(multisQRCodeCondition);
		// 1、现有的已存在的子码中有空的
		if(!CollectionUtils.isEmpty(childList)) {
			final MultistageLevelQRCode emptyMulti = childList.get(0);
			packScanData.setLayerCode(emptyMulti.getPackContent());
			packScanData.setLayerName(packStandardMap.get(emptyMulti.getPackLevel()));
			packScanData.setLayerSurplusSize(packStandardSubNumMap.get(emptyMulti.getPackLevel())); // 空层,数量为subNum
		}else if(childNum<packStandardSubNumMap.get(product.getBigLevel())){ // 2、若还有余位生成子码,生成一个返回
			final int layerLevel = bigLevelMultis.getPackLevel()-1; // 生成的码的级别
			final String layerCode = multistageLevelQRCodeService.generatedMultistageQRCode(bigLevelMultis.getEnterpriseCode(), 
					bigLevelMultis, bigLevelMultis.getPackContent(), layerLevel, Cons.CODE_CATEGORY_PREFIX_LAYER);
			packScanData.setLayerCode(layerCode);
			packScanData.setLayerName(packStandardMap.get(layerLevel));
			packScanData.setLayerSurplusSize(packStandardSubNumMap.get(layerLevel)); // 空层,数量为subNum
		}
		
	}

	/**
	 *@Title: validateScanCodeParams
	 *@Description: 验证包装管理扫码参数
	 *@return Response
	 *@author youjun
	 *@date 2017年8月16日 下午8:11:59
	 *@param packScanVo
	 *@return
	 */
	private Response validateScanCodeParams(final PackScanVo packScanVo) {

		final Response validateResponse = super.validateBasicParams(packScanVo, true, true);
		if(StringUtils.isBlank(packScanVo.getCode())) {
			return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "扫码code不能为空");
		}
		if(packScanVo.getCodeType()==null) {
			return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "扫码的码类型不能为空");
		}
		if(packScanVo.getOperationType()==null) {
			return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "操作类型不能为空");
		}
		return validateResponse;
	}

	/**(non-Javadoc)
	 * @throws ServiceException 
	 *@Title: scanOperationCode
	 *@Description: 
	 *@see com.sigmatrix.sc.handheld.inter.service.PackScanService#scanOperationCode(com.sigmatrix.sc.handheld.inter.web.vo.packmanage.PackScanOperationVo)
	 *@author youjun
	 *@date 2017年8月17日 下午3:27:46
	 */
	@Override
	public Response scanOperationCode(final PackScanOperationVo packScanOperationVo) throws ServiceException {

		try{
			Response validateResponse = validateScanCodeParams(packScanOperationVo);
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			if(packScanOperationVo.getProductId()==null) {
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "产品ID不能为空");
			}
			final String enterpriseCode = packScanOperationVo.getEnterpriseCode();
			int currentProductId = packScanOperationVo.getProductId(); // 当前产品ID
			final Map<String, Object> map = new HashMap<String, Object>();
			final QRCodeVo qRCodeVo = new QRCodeVo();
			qRCodeVo.setEnterpriseCode(enterpriseCode);
			qRCodeVo.setCode(packScanOperationVo.getCode());
			qRCodeVo.setCodeType(packScanOperationVo.getCodeType());
			qRCodeVo.setOperationType(packScanOperationVo.getOperationType());
			validateResponse = qRCodeService.queryCodeByCode(qRCodeVo, map, -1);
			if(validateResponse.getCode()!=Cons.RESPONSE_CODE_SUCCESS) {
				return validateResponse;
			}
			final ProductData product = (ProductData) map.get("product"); // 产品信息
			final Map<Integer, String> packStandardMap = product.getPackStandardMap(); // 包装规格map
			final int packLevel = product.getProductUnit().intValue(); // 产品的包装单位级别
			final int codeLevel = (int) map.get("codeLevel"); // 所扫码的级别
			final List<Integer> packStandardLevelList = product.getPackStandardLevelList(); // 包装level的集合,从小到大排序
			final int bigLevel = packStandardLevelList.get(packStandardLevelList.size()-1); // 最大包装级别
			final BaseQRCodeData qRCodeData = new BaseQRCodeData(); // 返回给手持的信息
			qRCodeData.setBigUnit(packStandardMap.get(bigLevel));
			qRCodeData.setPackUnit(packStandardMap.get(packLevel));
			qRCodeData.setPackUnderUnit(packStandardMap.get(packLevel-1));
			// 当前所扫码的产品ID
			int scanProductId = product.getProductId();
			FirstLevelQRCode firstLevelQRCode = null;
			MultistageLevelQRCode multistageLevelQRCode = null;
			if(codeLevel==1) {
				firstLevelQRCode = (FirstLevelQRCode) map.get("firstLevelQRCode");
				qRCodeData.setCode(firstLevelQRCode.getQrCode());
				qRCodeData.setFriendlyCode(firstLevelQRCode.getFriendlyCode());
				qRCodeData.setFriendlyCodeFront(firstLevelQRCode.getFriendlyCodeFront());
				qRCodeData.setFriendlyCodeEnd(firstLevelQRCode.getFriendlyCodeEnd());
				qRCodeData.setSeqNum(firstLevelQRCode.getSeqNum());
			}else{
				multistageLevelQRCode = (MultistageLevelQRCode) map.get("multistageLevelQRCode");
				qRCodeData.setCode(multistageLevelQRCode.getPackContent());
				qRCodeData.setFriendlyCode(multistageLevelQRCode.getFriendlyCode());
				qRCodeData.setFriendlyCodeFront(multistageLevelQRCode.getFriendlyCodeFront());
				qRCodeData.setFriendlyCodeEnd(multistageLevelQRCode.getFriendlyCodeEnd());
				qRCodeData.setSeqNum(multistageLevelQRCode.getSeqNum());
			}
			final int operationType = packScanOperationVo.getOperationType(); // 当前操作
			if(scanProductId!=currentProductId) {
				return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, "请扫描正确的产品码");
			}
			if(operationType==PackScanOperTypeEnum.GROUP_OR_FILL_BOX.getId()) { // 组/补箱操作,扫描的必须是包装码的下级码
				if(codeLevel!=packLevel-1) {
					return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
							new StringBuilder("组箱操作扫的必须是").append(packStandardMap.get(packLevel-1))
							.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
				}
			}else if(operationType==PackScanOperTypeEnum.SPLIT_BOX.getId()) { // 拆箱操作,扫描的是包装的下级码
				if(codeLevel!=packLevel-1) {
					return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
							new StringBuilder("拆箱操作扫的必须是").append(packStandardMap.get(packLevel-1))
							.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
				}
			}else if(operationType==PackScanOperTypeEnum.GROUP_OR_FILL_STACK.getId()) { // 组/补垛操作
				// 组/补垛操作:扫原垛下的箱,获得对应的垛码(顶级码)
				if(codeLevel!=packLevel) {
					return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
							new StringBuilder("组垛操作扫的必须是").append(packStandardMap.get(packLevel))
							.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
				}
			}else if(operationType==PackScanOperTypeEnum.SPLIT_STACK.getId()) { // 拆垛操作
				if(codeLevel!=packLevel) {
					return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
							new StringBuilder("拆垛操作扫的必须是").append(packStandardMap.get(packLevel))
							.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
				}
			}else if(operationType==PackScanOperTypeEnum.ADD_NEW_STACK.getId()) { // 新增垛操作
				if(codeLevel!=packLevel) {
					return new Response(Cons.RESPONSE_CODE_DATA_EXCEPTION, 
							new StringBuilder("新增垛操作扫的必须是").append(packStandardMap.get(packLevel))
							.append("，当前扫的是").append(packStandardMap.get(codeLevel)).toString());
				}
				
			}else{
				return new Response(Cons.RESPONSE_CODE_PARAM_INVALID, "暂不支持该操作");
			}
			return new Response(ResponseEnum.SUCCESS, qRCodeData);
		}catch(Exception e){
			throw new ServiceException(e);
		}
		
	}

	
}
